<?php

namespace App\Helpers;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use Monolog\Formatter\HtmlFormatter;
use Monolog\Formatter\JsonFormatter;
use Monolog\Formatter\LineFormatter;
use Monolog\Formatter\NormalizerFormatter;
use Monolog\Formatter\ScalarFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Monolog\Processor\ProcessIdProcessor;
use Monolog\Processor\UidProcessor;
use Monolog\Processor\WebProcessor;

//将日志记录格式化成一行字符串。

//用来将日志记录格式化成易读的HTML表格，主要适合发邮件。

//将日志记录编码成JSON.

//将 objects/resources 格式化成字符串，以便更方便地对其进行序列化/编码。

//用来将日志记录格式化到一个关联数组中，里面都是放标量值。

//用来将日志记录格式化到一个关联数组中，里面都是放标量值。

//Monolog文档https://github.com/Clarence-pan/monolog-zh-doc
class XLog
{
    public function __construct()
    {
        //
    }

    // 后续扩展其他类型日志

    /**
     * 说明：自定义日志
     *
     * @param any   $message 日志内容可以是数组、字符串、json等 目前支持数组格式化打印
     * @param any   $a       1、日志第二内容  2、日志保存路径
     * @param any   $b       当传入$a参数同时传入$b参数时 $a:日志第二内容  $b:日志保存路径
     * @param array $info    ['name' => '','format' => '']
     *
     * @return
     * @author  daixinguo (daixinguo57@163.com)
     */
    public static function info($message, $a = '', $b = '', $info = [])
    {
        //如果传入参数$b 则 $a 参数必须传入
        //如果不传入参数$b 且传入了参数$a  当$a 为数组时 表示 使用默认日志路径  当$a不是数组时表示 $a 参数为日志文件名
        //如果 $a $b 参数都传入 $a 为日志内容主体  $b 为日志文件名

        //原生第二个参数$context为数组时  日志记录 数组被转换为 json打印   修改为 调用$log->info()时只传入一个参数  如果有第二个参数  把第二个参数和第一个参数合并  写入日志
        $path = "logs/custom.log";
        if (empty($b)) {
            if (!empty($a)) {
                if (is_string($a) && strpos($a, ".log")) {
                    $path = "logs/" . $a;
                } else {
                    $context = is_array($a) ? self::formatMessage($a) : $a;
                }
            }
        } else {
            $context = is_array($a) ? self::formatMessage($a) : $a;
            // $context = self::formatMessage($a);
            $path = "logs/" . $b;
        }
        $name = !empty($info['name']) ? $info['name'] : "xunlu";
        $log = new Logger($name);
        //$stream_handler = new StreamHandler(storage_path($path), Logger::INFO); //不用这个简单的日志处理器

        $RotatingFile = new RotatingFileHandler(storage_path($path), 14, Logger::INFO);

        //添加一个唯一的标识到日志记录中。
        $uid_obj = new UidProcessor();
        $log->pushProcessor($uid_obj);
        //添加进程ID到日志记录中。
        $pid_obj = new ProcessIdProcessor();
        $log->pushProcessor($pid_obj);
        //添加当前请求的 URI, 请求方法和客户端 IP 到日志记录中。
        $http_info = new WebProcessor();
        $log->pushProcessor($http_info);

        //日志格式化 参数  LineFormatter(?string $format = null, ?string $dateFormat = null, bool $allowInlineLineBreaks = false, bool $ignoreEmptyContextAndExtra = false)
        //默认 [%datetime%] %channel%.%level_name%: %message% %context% %extra%\n
        // if (!empty($context)) {
        // 	$format = "[%datetime%] %channel%.%level_name% ※※※※※※※※ %extra%\n%message%\n%context%\n\n";
        // } else {
        // 	$format = "[%datetime%] %channel%.%level_name% ※※※※※※※※ %extra%\n%message%\n\n";
        // }
        //
        //原生第二个参数为数组时  日志记录 数组被转换为 json打印   修改为 调用$log->info()时只传入一个参数  如果有第二个参数  把第二个参数和第一个参数合并  写入日志
        $format = "=====================================================================================================================================";
        $format .= "\n[%datetime%] %channel%.%level_name% ※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※";
        $format .= "\n-------------------------------------------------------------------------------------------------------------------------------------";
        $format .= "\n%message%\n";
        $format .= "\n[Request info]";
        $format .= "\n%extra%\n\n";
        $dateFormat = 'Y-m-d H:i:s';
        $allowInlineLineBreaks = true;
        $ignoreEmptyContextAndExtra = true;
        //格式化 日志
        if (!empty($info['format'])) {
            switch (strtolower($info['format'])) {
                case "html":
                    $RotatingFile->setFormatter(new HtmlFormatter());
                    break;
                case "normalizer":
                    $RotatingFile->setFormatter(new NormalizerFormatter());
                    break;
                case "scalar":
                    $RotatingFile->setFormatter(new ScalarFormatter());
                    break;
                case "json":
                    $RotatingFile->setFormatter(new JsonFormatter());
                    break;
                default:
                    //默认 使用 LineFormatter
                    $RotatingFile->setFormatter(new LineFormatter($format, $dateFormat, $allowInlineLineBreaks, $ignoreEmptyContextAndExtra));
            }
        } else {
            $RotatingFile->setFormatter(new LineFormatter($format, $dateFormat, $allowInlineLineBreaks, $ignoreEmptyContextAndExtra));
        }

        $log->pushHandler($RotatingFile);

        $message = self::formatMessage($message);

        //当记录json数据时 进行格式化输出 方便阅读  这个太难啦  先放弃吧
        //[{"a":5,"b":6,"c":7},{"a":5,"b":[{"a":1,"b":1,"c":1},{"a":1,"b":1,"c":1}],"c":7}]

        $data = isset($context) ? $message . "\n" . $context : $message;
        $log->info($data);

        // add records to the log
        //$log->warning($data);
        //$log->error($data);
    }

    /**
     * Format the parameters for the logger.
     *
     * @param mixed $message
     *
     * @return mixed
     */
    protected static function formatMessage($message)
    {
        if (is_array($message)) {
            return var_export($message, true);
        } elseif ($message instanceof Jsonable) {
            return $message->toJson();
        } elseif ($message instanceof Arrayable) {
            return var_export($message->toArray(), true);
        }

        return $message;
    }
}
